perm filename MCTCST.PUB[HAL,HE] blob
sn#133595 filedate 1974-12-04 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00012 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 .ctc: NEWSEC COMPILE-TIME CONSTRUCTS
C00005 00003 .pvs: NEWSS PLANNING VALUES
C00012 00004 .NEWSS PLANNING VARIABLES
C00015 00005 .NEWSSS ATOMS
C00019 00006 .NEWSSS |EXPRESSIONS, CLAUSES, STATEMENTS, AND FORMS|
C00024 00007 .asr:NEWSS ASSERTIONS
C00035 00008 .cex:NEWSS CONDITIONAL EXPANSION
C00042 00009 .NEWSSS BINDING BOOLEANS
C00045 00010 .newsss PICK
C00048 00011 .NEWSSS PLAN FOREACH
C00051 00012 .NEWSS THE COMPILE-TIME CHECK STATEMENT
C00053 ENDMK
C⊗;
.ctc: NEWSEC COMPILE-TIME CONSTRUCTS
.NEWSS INTRODUCTION
AL seeks to maintain a fairly accurate planning model of the
expected state for each point in the execution of a program. This
planning model includes the expected values of runtime variables,
together with a number of symbolic assertions about objects,
relations between frames, constraints on trajectory endpoint
conditions, and other information, and is important throughout the
system. At the lowest level, it provides "target" locations for the
calculation of proper trajectories. Beyond this, planning
information is used to direct conditional expansion of input programs
and library routines, and provides a basis for decisions on how to
translate the various high-level, assembly-oriented constructs into
runnable manipulation programs.
A number of language constructs are provided in AL to allow the user
to access this model and to assist in maintaining it. These
facilities are described in this chapter, which also discusses
language features such as conditional compilation for increasing the
convenience of programming and the flexibility of programs. The use
of the planning model facilities for object descriptions and by the
"very high level" components of AL is discussed more fully in {secref vhl}.
.pvs: NEWSS PLANNING VALUES
One very important piece of information about a variable
is its %4planning value%*, which is the compiler's estimate of what value
the variable will have at some point in the program execution.
As with other aspects of the planning model, planning values have
many uses in AL. One especially important use is in trajectory
calculation. Although provisions are made to modify any preplanned
trajectory before executing it, the current scheme requires that
at least a roughly accurate value be available at compile time if
smooth trajectories are desired. This was discussed in {sssref mrt}.
Typically, planning values are updated whenever the compiler encounters
something that it has reason to expect will cause the runtime value to
change. For instance, the assignment statement
.unfill
foo ← 3
.refill
will cause the compiler to emit code to set foo to 3 and will cause it to
change the planning value of foo to become 3. Similarly
.unfill
a ← b + c
.refill
will cause the planning value of variable %4a%* to be set to the planning value
of %4b%* plus the planning value of %4c%*, provided that both %4b%* and %4c%* have
known planning values. If one of the planning values isn't known, then
%4a%* gets the special planning value %4undefined%*,
which is also used as an initial
planning value at the time a variable is declared.
Motion statements also
can cause planning values to be updated. For instance,
.unfill
MOVE yellow TO bar
.refill
will cause the planning value of yellow to be set to the planning
value of bar. Also, the planning value of any variables affixed to
yellow will be updated appropriately.
The planning value of a variable may be retrieved by use of the construct
.unfill
α#(<variable name>)
.refill
which yields a constant equal to the planning value of the variable.
For example,
.unfill
b ← 3;
a ← α#(b);
.bull
has the same effect as
b ← 3;
a ← 3;
.refill
Although the compiler makes an effort to keep track of the expected
runtime state of variables, it must sometimes be given explicit
assistance. For example, it is difficult for the compiler to
maintain unambiguous planning values over conditional statements, as in
this example:
.unfill
SCALAR s1, s2;
VECTOR v1;
s1 ← 100;
IF s2 > 3 THEN
BEGIN
v1 ← VECTOR(1,2,3);
s1 ← 101;
α{α#(s1) = 101α}
α{α#(v1) = VECTOR(1,2,3)α}
END
ELSE
BEGIN
v1 ← VECTOR(1,2,4);
α{α#(v1) = VECTOR(1,2,4)α}
α{α#(s1) = 100α}
END;
α{α#(v1) = UNDEFINEDα}
α{α#(s1) = UNDEFINEDα}
.refill
Although the compiler may eventually be smart enough to resolve a
number of such cases, for the moment the user must tell the compiler
what planning value to use thereafter.
The compile-time assignment statement:
.unfill
<variable> ←← <constant expression>
.refill
is provided to set the planning value of a variable. Such assignments
affect only the planning value; no code is emitted, and the runtime
value of the variable remains unaffected. Thus, both
.unfill
v ← VECTOR(3,3,3)
.bull
and
v ←← VECTOR(3,3,3)
.refill
set the planning value of %4v%* to VECTOR(3,3,3), but only the
first form causes the runtime value of %4v%* to be changed.
Planning values provide a useful way to generate error estimates,
as in
.unfill
FRAME f1, f2, f3;
:
AFFIX f1 TO f2 RIGIDLY;
:
AFFIX f2 TO yellow;
MOVE yellow TO f3;
.comt 12
α{Moving the yellow arm will cause the runtime values of frames
f1 and f2, which are affixed to it, to be updated as well.α}
.end
WHILE ABS(LOC(f1)-LOC(α#(f1))) > .25*CM DO
BEGIN
:
α{%4Make a correction%*α}
α{%4Measure f1%*α}
:
END;
.refill
Although it is theoretically possible for the user
to fill in the relevant nominal values explicitly, in practice this
can be rather inconvenient, especially when the planning values are
derived from some complicated computation. Furthermore, the availability
of planning values
offers significant advantages with regard to program flexibility, since
changing a particular expected value will not, in general, require
substantial changes in program text.
.NEWSS PLANNING VARIABLES
Planning variables allow the user to take advantage of the
compile-time computation and planning value maintenance facilities
of AL without incurring the runtime overhead of having regular
variables in cases where only their planning values are ever used.
Typical uses include attaching symbolic names to constants, use of temporary
variables in compile-time calculations, object modelling, access to
symbolic assertions in the planning model, passing "advice" to
high-level language primitives and to library routines.
.newsss |ALGEBRAIC PLANNING VARIABLES|
Algebraic planning variables are declared by the construct
.unfill
PLANNING <data-type> <identifier 1>, ... , <identifier n> .
.bull
For instance,
PLANNING SCALAR a, b, c;
PLANNING DISTANCE SCALAR d1, d1;
PLANNING FORCE VECTOR f1, f2, lift;
PLANNING TRANS t;
.refill
Such variables may have planning values, but have no runtime existence
whatsoever. This means that they may appear on the left hand side of
planning assignment statements (i.e., the "α←α←" form), but not
of regular assignment statements (i.e., the "α←" form). Similarly,
a planning variable may not appear in an arithmetic expression,
although its planning value (that is, α#(<ct#var>) ) may do so. Thus,
the following are legal:
.unfill
PLANNING SIMPLE a, b;
SIMPLE v;
a ←← 3;
b ←← α#(a) - .01;
v ← 2 + α#(a);
v ← α#(v) - v*α#(b);
b ←← UNDEFINED; α{%4this causes b to lose its planning value%*α}
.bull
These, however, are not legal:
PLANNING SIMPLE a, b;
SIMPLE v;
a ← 3;
v ← a; α{%4Note that no coercions to planning values are ever made.%*α}
b ← a; α{%4Ditto%*α}
v ← UNDEFINED; α{%4UNDEFINED has no runtime meaning.%*α}
.refill
.NEWSSS ATOMS
In addition to the regular runtime data types, there are several
additional types that (presently) can occur only with planning
variables. These variables follow the usual rules concerning
planning value assignment and propagation, except that their "value" is
not an arithmetic quantity. Instead, it is the internal structure
associated with some construct in the language. Perhaps the most
important of these variable types is the %4atom%*, which is a variable
whose (planning) value is the name of another variable.
Atoms are declared by the construct
.unfill
ATOM <id1>, ... , <idn>;
.refill
Note that the word "PLANNING" is not needed, since an atom is purely a
planning construct.
Planning values may be assigned to atom variables by use of the construct
.unfill
<atom name> ←← <variable name>
.bull
as in
ATOM a1, a2, a3;
DISTANCE SCALAR d;
a1 ←← d;
a2 ←← a3;
α#(a2) ←← α#(a1);
.COMT 12
α{Now, α#(a1)="d", α#(a2)="a3", α#(a3)="d"α}
.end
.refill
Notice that α#(<atom>) yields the name of a variable; its effect is
as if the variable itself were used. Thus,
.unfill
d ← 100*feet
.bull
and
α#(a1) ← 100*feet
.refill
will both have the same effect. Also, note that assignment to an atom
constitutes the only case where the name of a variable may appear on the
right hand side of a planning assignment statement.
Atoms serve a number of useful purposes, the most prominent of which
include serving as "key words" in symbolic assertions, providing a means
for retrieving and using variables as object properties, and
as a means for adapting the same piece of program text to perform
different versions of the same task. For instance,
.unfill
ATOM arm, h;
FRAME hole1,hole2;
:
arm ←← blue;
h ←← hole1;
:
MOVE α#(arm) TO α#(h);
:
h ←← hole2;
:
MOVE α#(arm) TO α#(h);
:
.refill
Here, the MOVE statement has been typed out twice, so the actual saving
is rather small. In practice, however, it is common to place such statements
inside a macro or library routine (see {ssref lib}), in which case the
gain in convenience can be appreciable. Similarly, the atoms "arm" and "h"
can be given planning values by means of the BIND construct in a planning
conditional expansion (see {ssref cex}).
.NEWSSS |EXPRESSIONS, CLAUSES, STATEMENTS, AND FORMS|
Another very important
type is the %4expression%*, which takes as its planning value the internal
structure associated with an expression in the language. These variables
are declared by the construct
.unfill
EXPRESSION <id1>, ... ,<idn>;
.refill
Again, note that the word "PLANNING" is not used. If desired,
an atom or expression variable may be restricted to values of some particular
algebraic
type by inclusion of the appropriate additional declarators. For instance,
.unfill
DISTANCE ATOM da;
VECTOR ATOM va;
FORCE VECTOR ATOM fva;
TRANS EXPRESSION te1, te2;
.refill
Other planning only types include %4statement, clause,%* and %4form%*.
Statement variables
take as their planning values the internal structure associated with a statement.
Clause variables take as their planning values the structure associated with
clauses, such as "TO#⊗" and "WITH#DURATION#≥#3*SEC".
Clauses, statements and expressions are primarily useful as a means of passing explicit
"advice" on to a library routine or high-level primitive. In addition,
statement variables are frequently very useful as placeholders in partially
written code.
%4Form%* variables hold references to assertions in the compiler's planning
model and are discussed in more detail in subsequent sections. One use
is to allow a user to remember the name of an assertion in such a way
as to facilitate undoing it later.
Planning values may be assigned to clause, statement, expression, and form variables
by use of the appropriate construction functions to produce constants
of the appropriate types. Thus we might have:
.unfill
TRANS t1;
FRAME widget;
ATOM height;
CLAUSE c;
EXPRESSION e;
STATEMENT s;
FORM f;
:
f ←← FORM(height, widget, 100);
e ←← EXPRESSION(t1*ypark);
s ←← STATEMENT(MOVE YELLOW TO α#(e));
c ←← CLAUSE(VIA widget);
.comt 12
α{Note that α#(e) will not be evaluated until the planning
value of s is used; that is, until α#(s) is used as a statement somewhereα}
.end
.refill
As one might expect, the argument to an %4expression%* primitive is an expression,
the argument to %4clause%* is a clause, and
and the argument to a %4statement%* primitive is a statement. These compile-time
functions return the internal structures associated with their arguments; when
this structure is stored into a planning variable of the appropriate type
then the planning value of that variable becomes the expression or statement.
Thus,
.unfill
e ←← EXPRESSION(t1*t2*f1);
c ←← CLAUSE(VIA widget);
s ←← STATEMENT(MOVE YELLOW TO f3 α#(c));
:
f3 ← α#(e)
α#(s);
.bull
and
f3 ← t1*t2*f1;
MOVE yellow TO f3 VIA widget;
.refill
will have exactly the same effect.
.asr:NEWSS ASSERTIONS
In addition to planning values, the planning model used by AL
includes a number of facts that are usefully expressed as symbolic
assertions. These facts include object descriptions, semantic information
about what is in the hands, state information about required approaches
for motions,and relations between frames. Internally, all facts
(whether added to the data base by the compiler or explicitly by the
user) are represented as forms of constant elements
such as one might find as planning values for some variable or another.
For example,
.unfill
FORM(Roses, are, red);
FORM(WEIGHT, engine_block, 3.5*POUNDS);
FORM(AFFIXED, f1, TO, f2, BY, t3, RIGIDLY);
FORM(v1, COMPUTED_BY, EXPRESSION(a*v2+v3) );
.refill
are typical of the sort of forms which one might have in the data base.
Readers familiar with recent research in artificial intelligence will
no doubt recognize the similarity of many of the constructs presented in this
section with comparable features in modern AI languages. A detailed
discussion of this relation or of implementation details is beyond the
scope of this paper. However, perhaps it should be pointed out again
that the assertion mechanisms in AL are a planning-time construct without
any runtime existence. The system attempts to keep track of what facts are
expected to be true at each point in the program by associating with each
fact in the data base a set of "worlds" corresponding to each place that
a fact is true. Some further discussion of this mechanism may be found in
{SSREF wld}.
.NEWSSS THE ASSERT STATEMENT
Symbolic assertions may be added to the data base by use of the statement
.unfill
ASSERT <form>
.refill
where <form> is either the planning value of a FORM variable or a call
on the FORM construction primitive,
.unfill
FORM(<element 1>,<element 2>, ... ,<element n>)
.refill
In general, each <element> must be something that can appear on the right
hand side of a planning assignment statement (i.e., the "α←α←" assignment).
This includes constants, expressions involving only constants (including
α#(<variable>) ), variable names, and the results of construction functions
like EXPRESSION, STATEMENT, and FORM. (Also, the BIND construct is allowed,
but this is discussed later). For instance,
.unfill
ATOM holds, SLOT, headtype1, HEX, now, is, the, time;
.COMT 12
α{We are following a convention that %*individuals%4 are
in lower case, and %*classes or properties%4 are in upper
case.α}
.END
STATEMENT PARKING_METHOD;
FRAME driver1;
FORM formvar;
:
ASSERT FORM(yellow, holds, driver1);
ASSERT FORM(SLOT, headtype1, HEX, 0.53);
ASSERT FORM(PARKING_METHOD, yellow,
STATEMENT(MOVE YELLOW TO YPARK));
formvar ←← FORM(now, is, the, time);
ASSERT α#(formvar)
.refill
The actual meaning of an asserted pattern is generally determined by
whatever conventions the user may wish to establish. However, a few
pattern types, such as those for affixment or those used by the very
high level routines for object descriptions, are "understood" and
used by the compiler. (As mentioned earlier, AL includes a number
of predeclared atoms to act as key words in these reserved patterns.)
The user can cause serious confusions by
improper introduction or deletion of such patterns, although,
used properly, they provide a valuable tool for communication with the
planning model.
.NEWSSS THE DENY STATEMENT
Generally,
assertions will remain "true" in the compiler's world model until
explicitly deleted or, in the case of assertions used by the
compiler, as a side effect of processing some statement. Any
assertion may be undone by use
of the DENY construct, which is similar to ASSERT:
.UNFILL
DENY FORM(IN, HAND, screwdriver);
DENY α#(formvar);
.REFILL
.NEWSSS CONSTRAINT ASSERTIONS
In addition to planning values and symbolic assertions, the system's
planning model may include constraint information delimiting the
range of values that a variable may take on. Much of this
information is expressed internally by means of mathematical
constraints on scalar variables that represent degrees of freedom in
object locations.
For instance, if a flat surface of an object is flush up
against another flat surface, then (in the absence of other
constraints) the object will have two translational and one
rotational degrees of freedom.
These constraints are generally derived from the semantics of the
various "high level" operations, the object descriptions, and
certain "standard" assertional patterns. (See {ssref var} for more
details.) In addition, however, a user can use the construct
.unfill
ASSERT <expression><relation><constant>
.refill
in order to state a constraint relationship explicitly.
The <relation> may be any of "≤","<","=",">", and "≥". At present,
<expression> is restricted to be a linear form involving only scalar
variables or the dot product of two vectors. For instance,
.unfill
DISTANCE SCALAR a, b, c;
VECTOR v;
:
ASSERT 3*a + 4*b - 2*c ≤ 2*INCHES;
ASSERT v . Z > 0.25;
.refill
This construct is primarily intended for use in debugging the higher
level operators and in writing library routines that are to be
used with such operators. It is being described here in the interests
of completeness and because reference is made to it in {ssref var}.
.NEWSSS STANDARD USES FOR ASSERTIONS
The user may use the assertional database to store arbitrary information.
Certain patterns, however, are given special meaning in AL. For example,
in our discussion of deproaches, we implied that the compiler keeps track
of each frame's associated deproach by means of assertions. Thus, to
give the frame f1 a deproach transformation t1, one writes:
.unfill
ASSERT FORM(DEPROACH, f1, t1) .
.refill
Another standard use is for affixments. One effect of the statement
.unfill
AFFIX f1 TO f2
.bull
is the assertion
ASSERT FORM(AFFIXED, f1, f2) .
.refill
Similarly, the object descriptions used by the assembly-oriented operations,
as well as the planning model associated with such operations, rely quite
strongly on standard assertion patterns.
A fuller discussion of some of these patterns may be found in {ssref obd}.
However, this document does not purport
to list fully all the patterns that are actually used by AL, although
it should give the reader some idea of their approximate extent and
should provide a fair indication of how they are actually used.
.cex:NEWSS CONDITIONAL EXPANSION
It is frequently desirable to write a fairly general piece of source
code that produces different object code, depending on the specific
task to be performed and on the compiler's model of the expected
runtime environment.
.NEWSSS PLAN IF
The principal mechanism provided for this
purpose is the plan-time conditional construct, which behaves like
a conventional Algol "IF", except that it is resolved at compile
time, with only the the "expanded" part having any effect on the
compiler's world model. The syntax is:
.UNFILL
PLAN IF <condition> THEN
<then-part>
ELSE
<else-part>
.REFILL
where the "ELSE" component may be omitted if desired. The condition
may be any boolean expression which can be completely evaluated at
plan-time. For instance:
.UNFILL
PLAN IF α#(blue) ≠ bpark THEN
MOVE blue TO bpark;
.REFILL
which says that if the planning value of the blue arm is not equal to
bpark (that is, if the last motion statement for the blue arm was not
to its parked position), then insert a statement to move it there.
Similarly, suppose we have a general routine for putting screws in
holes. Further, assume that we are using a plan-time variable
"chamfer" to contain the width of chamfering around the hole. Then
the routine might have something like:
.UNFILL
PLAN IF α#(chamfer) > .25*INCHES THEN
BEGIN
.COMT 16
α{Code to perform a simple "straight in" insertionα}
.end
END
ELSE
BEGIN
.comt 16
α{Code to perform some sort of a search to
get the screw into the holeα}
.end
END;
.REFILL
.NEWSSS TESTING FOR ASSERTIONS
The presence in the data base of a symbolic form can be tested by use
of the %4asserted%* construct, as in
.UNFILL
PLAN IF ASSERTED(FORM(IN,TOOLRACK,SCREWDRIVER)) THEN
BEGIN
.COMT 16
α{Code to fetch the screwdriver out
of the tool rackα}
.END
END;
.bull
In general,
ASSERTED(<form>)
.refill
returns "true" whenever the <form> is asserted in the planning model
at the point that the test is made. Thus,
.unfill
FORM f;
TIME t;
:
PLAN IF ASSERTED(α#(f)) THEN
BEGIN
t←3*SEC;
DENY α#(f);
END;
PLAN IF ASSERTED(α#(f)) THEN
BEGIN
t←4*SEC;
END;
:
.bull
would expand into
FORM f;
TIME t;
:
t←3*SEC;
DENY α#(f);
:
.refill
Furthermore, note that ASSERTED(<form>) acts like a boolean primary and
can enter into boolean expressions in the usual way. For instance,
.unfill
PLAN IF ASSERTED(FORM(GOES_IN,shaft1,hole1))
∧¬ASSERTED(FORM,IN,shaft1,hole1)) THEN
BEGIN
PLAN IF ASSERTED(FORM(THREADED,shaft1)) THEN
BEGIN
.COMT 20
α{code to insert a threaded screwα}
.END
ASSERT FORM(SCREWED,shaft1);
END
ELSE
BEGIN
.COMT 20
α{code to insert a smooth pinα}
.END
ASSERT FORM(SLIPPED_IN,shaft1);
END;
ASSERT FORM(IN,shaft1,hole1);
END;
.REFILL
.NEWSSS THE ANYTHING CONSTRUCT
Frequently, one may want to test a whole class of asserted forms at
once. For instance, suppose we may want to know if the blue hand is
available for some task or another. We can keep track of what is in
the hand by means of assertions like
.UNFILL
ASSERT FORM(blue,HOLDS,widget);
.REFILL
However, it is frequently inconvenient, and sometimes impossible,
to test all possibilities explicitly, as in:
.UNFILL
PLAN IF ¬ASSERTED(FORM(BLUE,HOLDS,widget))
∧ ¬ASSERTED(FORM(BLUE,HOLDS,frob)) ∧ . . . THEN
BEGIN
α{%4whatever%*α}
END;
.REFILL
The reserved word ANYTHING is provided as a wild card to avoid this
difficulty. Thus, we can write:
.UNFILL
PLAN IF ¬ASSERTED(FORM(BLUE,HOLDS,ANYTHING)) THEN
BEGIN
α{%4whatever%*α}
END;
.REFILL
One restriction of the current implementation is that one is not allowed
to assert forms containing wild card elements like ANYTHING or the
BIND construct discussed in the next section. One can only use them in
constructs like ASSERTED, which don't try to add anything to the data base.
.NEWSSS BINDING BOOLEANS
Frequently a simple wild card element like ANYTHING does not suffice.
For example,
the user may want to execute different code, depending on what is
supposed to be in the blue hand. This situation is provided for by
the use of
.unfill
BIND(<ct variable>)
.refill
as one or more of the elements in a FORM pattern being tested by the ASSERTED
construct. Generally, BIND(var) acts like a "wild card" that matches
any element in the correct position in a form that has the same type as
var. It has the additional side effect of setting the planning value
of var to be the value of the element it matched. For example,
.UNFILL
ATOM thing;
PLANNING FRAME where;
:
ASSERT FORM(blue,HOLDS,frob);
ASSERT FORM(CORRECT_SPOT_FOR,frob,FRAME(ROT(Y,180),VECTOR(1,2,3)) );
ASSERT FORM(CORRECT_SPOT_FOR,widget,
FRAME(ROT(Y,180),VECTOR(4,5,6)) );
:
PLAN IF ASSERTED(FORM(blue,HOLDS,BIND(thing)) ) THEN
BEGIN
α{%4Here, α#(thing) will get "FROB"%*α}
IF ASSERTED(FORM(CORRECT_SPOT_FOR,α#(thing),BIND(where))) THEN
BEGIN
MOVE blue TO α#(where);
α{%4some more code%*α}
END
ELSE
BEGIN
α{%4some sort of error message, perhaps%*α}
END;
END;
.bull
Would expand into
MOVE blue TO FRAME(ROT(Y,π*RAD),VECTOR(1,2,3));
α{%4some more code%*α}
.REFILL
This construct is especially useful for library routines, which can use
it to retrieve properties of objects and then take appropriate action.
.newsss PICK
One frequent use of assertions in to specify a number of properties of some
object or variable. For instance,
.UNFILL
ASSERT FORM(HEIGHT,widget,100*CM);
ASSERT FORM(WEIGHT,widget,200*GM);
ASSERT FORM(DEPROACH,widget,FRAME(ROT(Y,π*RAD),X));
.REFILL
These properties can, of course, be retrieved by means of the ASSERTED
construct, as in
.unfill
PLAN IF ASSERTED(FORM(HEIGHT,widget,BIND(h)) ) THEN
BEGIN
MOVE YELLOW TO widget + α#(h);
:
END
ELSE
BEGIN
α{%4perhaps some sort of error message%*α}
END
.refill
Unfortunately, this sort of thing can be rather inconvenient for
fetching values, since it requires explicit use of an auxiliary
variable and a fairly long statement. In such cases the PICK construct
can be used instead, as in
.unfill
MOVE yellow TO widget + PICK(FORM(HEIGHT,widget,BIND(*)) )
.refill
In general, PICK has the form
.unfill
PICK(<form pattern>)
.refill
where the <form pattern> contains "BIND(*)" as %4one%* of its terms. PICK
causes the compiler to retrieve a form that is in the planning model
and which matches the template provided by the <form#pattern>. The
value in the form from the data base corresponding to the "BIND(*)" term
in the template pattern is then returned as the value for PICK.
Note that the argument template can also contain additional instances
of ANYTHING and BIND(<variable>). These are bound in the usual way.
For instance,
.unfill
ASSERT FORM(gadget,fits,onto,widget,at,FRAME(NILROT,X) );
:
obj ←← PICK(FORM(gadget,fits,onto,BIND(*),ANYTHING,BIND(locn)) );
.refill
would set the planning value of obj to "widget" and that of locn to
FRAME(NILROT,X).
.NEWSSS PLAN FOREACH
Sometimes, there may be several assertions in the data base that could
satisfy a given FORM retrieval pattern. For instance,
.UNFILL
ASSERT FORM(s1,SCREWS,INTO,h1);
ASSERT FORM(s2,SCREWS,INTO,h2);
ASSERT FORM(s3,SCREWS,INTO,h3);
:
PLAN IF ASSERTED(FORM(BIND(s),SCREWS,INTO,BIND(h))) THEN
BEGIN
:
END
.REFILL
In such cases, the compiler would arbitrarily pick one of the
eligible patterns to use as its template for performing any
requested bindings. Suppose, however, that the user wants to perform
some action for %4each%* pattern that matches, rather than for only one.
For instance, he may want to insert all the screws into their
corresponding holes. The PLAN FOREACH construct is intended
to allow this sort of thing.
.UNFILL
PLAN FOREACH <form> DO
<statement>
.REFILL
This construct will cause <statement> to be compiled once for each
instance of <pattern> that finds a match in the data base.
For instance, a library routine that fastens down a head to an engine
block by means of bolts which can be inserted in any order might
include a sequence like:
.UNFILL
ATOM bolt, hole_id, head_id;
:
PLAN FOREACH FORM( BIND(bolt),FASTENS,α#(head_id)) DO
BEGIN
PLAN IF ASSERTED(FORM(α#(bolt),FITS,INTO,BIND(hole_id))) THEN
INSERT α#(bolt) INTO α#(hole_id)
ELSE
BEGIN
PLAN ERROR(bolt,"doesn't fit into",hole_id);
END;
END;
.bull
If we then have assertions:
ASSERT FORM(b1,FASTENS,pumphead);
ASSERT FORM(b2,FASTENS,pumphead);
ASSERT FORM(b3,FASTENS,pumphead);
ASSERT FORM(b1,FRITS,INTO,h1);
ASSERT FORM(b2,FITS,INTO,h2);
ASSERT FORM(b3,FITS,INTO,h3);
.REFILL
and call our library routine to put on pumphead, the above fragment
would expand into
.UNFILL
INSERT b1 INTO h1;
INSERT b2 INTO h2;
INSERT b3 INTO h3;
.REFILL
.NEWSS THE COMPILE-TIME CHECK STATEMENT
Since library routines will be commonly used, it is necessary
to have some way of checking that necessary preconditions are met as
the first steps of the library routine. The way this is done is with
the %4check%* statement. A simple example:
.unfill
CHECK α#(s1)=3 ∧ α#(s2)>5
.refill
The contents of the check may be any
boolean expression, including checks on the current world model. The
check is only made at compile-time; if the check is not satisfied,
the compiler will generate an error message.
The effect of this statement is exactly like that of
.UNFILL
PLAN IF ¬(α#(s1)=3 ∧ α#(s2)>5 THEN
PLAN ERROR("Check statement failed") .
.REFILL